package com.test45_JUC;

import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.*;

/**
 * 原子操作类
 */
public class Demo04_Atomic {

    public static void main(String[] args) throws Exception {
        // test1();
        // test2();
        // test3();
        // test4();
        // test5();
        // test6();
        // test7();
        test8();
    }

    /**
     * 基本类型：AtomicInteger、AtomicLong、AtomicBoolean
     */
    public static void test1() throws Exception {
        AtomicLong num = new AtomicLong(0);
        for (int x = 0; x < 3; x++) {
            new Thread(() -> {
                System.out.printf("【%s】数据的加法计算：%d %n", Thread.currentThread().getName(), num.addAndGet(100));
            }).start();
        }
        TimeUnit.SECONDS.sleep(1);
        System.out.println("【计算完成】最终的计算结果为：" + num);
    }

    /**
     * CAS方法实现修改操作
     */
    public static void test2() {
        AtomicLong num = new AtomicLong(100L);
        System.err.println("x【原子数据修改】数据修改的结果：" + num.compareAndSet(200L, 300L));
        System.err.println("x【原子数据获取】新的数据内容：" + num.get());
        System.out.println("y【原子数据修改】数据修改的结果：" + num.compareAndSet(100L, 300L));
        System.out.println("y【原子数据获取】新的数据内容：" + num.get());
    }

    /**
     * 数组原子操作类
     * AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray
     */
    public static void test3() {
        String[] datas = new String[] {
                "www.yootk.com",
                "edu.yootk.com",
                "muyan.yootk.com"
        };
        AtomicReferenceArray<String> array = new AtomicReferenceArray<>(datas);
        System.out.println("【原子数据修改】数据修改的结果：" + array.compareAndSet(2, "muyan.yootk.com", "book.yootk.com"));
        System.out.print("【原子数据获取】数组内容：");
        for (int x = 0; x < array.length(); x++) {
            System.out.print(array.get(x) + "、");
        }
    }

    /**
     * 引用类型原子操作类
     * AtomicReference：引用类型原子类
     * AtomicStampedReference：带有引用版本号的原子类
     * AtomicMarkableReference：带有标记的原子引用类型
     */
    public static void test4() {
        {
            Book book = new Book("Java就业编程实战", 69.8);
            AtomicReference<Book> ref = new AtomicReference<>(book);
            ref.compareAndSet(book, new Book("Spring就业编程实战", 67.8));
            System.out.println(ref);
        }
        {
            // 直接存储的是一个匿名对象，没有栈内存的指向
            // 无法实现CAS的数据修改操作，之所以不能够修改就说因为无法与原是保存的数据内容进行有效的匹配
            AtomicReference<Book> ref = new AtomicReference<>(new Book("Java就业编程实战", 69.8));
            ref.compareAndSet(new Book("Java就业编程实战", 69.8), new Book("Spring就业编程实战", 67.8));
            System.out.println(ref);
        }
    }

    /**
     * AtomicStampedReference
     */
    public static void test5() {
        Book book1 = new Book("Java就业编程实战", 69.8);
        Book book2 = new Book("Spring就业编程实战", 67.8);
        // 1代表版本编号，按照正常的设计，每一次修改之后版本号要+1
        AtomicStampedReference<Book> ref = new AtomicStampedReference<>(book1, 1);
        // 版本号不匹配，无法进行内容的修改
        System.err.println("x【引用内容修改】" + ref.compareAndSet(book1, book2, 3, 5));
        System.err.println("x【原子引用数据】版本戳：" + ref.getStamp() + "\t存储内容：" + ref.getReference());
        // 版本号匹配成功，进行更新
        System.out.println("y【引用内容修改】" + ref.compareAndSet(book1, book2, 1, 2));
        System.out.println("y【原子引用数据】版本戳：" + ref.getStamp() + "\t存储内容：" + ref.getReference());
    }

    /**
     * AtomicMarkableReference
     */
    public static void test6() {
        Book book1 = new Book("Java就业编程实战", 69.8);
        Book book2 = new Book("Spring就业编程实战", 67.8);
        // 在数据修改之前要进行当前标记状态的判断，标记状态不符合要求，无法修改成功
        AtomicMarkableReference<Book> ref = new AtomicMarkableReference<>(book1, true);
        System.err.println("x【引用内容修改】" + ref.compareAndSet(book1, book2, false, true));
        System.err.println("x【原子引用数据】标记：" + ref.isMarked() + "\t存储内容：" + ref.getReference());
        // 版本号匹配成功，进行更新
        System.out.println("y【引用内容修改】" + ref.compareAndSet(book1, book2, true, true));
        System.out.println("y【原子引用数据】标记：" + ref.isMarked() + "\t存储内容：" + ref.getReference());
    }

    /**
     * 属性原子操作类
     * AtomicIntegerFieldUpdater：原子整型成员修改器
     * AtomicLongFieldUpdater：原子长整型成员修改器
     * AtomicReferenceFieldUpdater：原子引用成员修改器
     */
    public static void test7() {
        {
            AtomicLongFieldUpdater updater = AtomicLongFieldUpdater.newUpdater(Book.class, "id");
            // 默认使用CAS的方式来实现修改器的对象实例获取，必须使用volatile关键自定义
            System.out.println(updater.getClass());
        }
        {
            Book book = new Book(1002, "Java就业编程实战", 69.8);
            book.setId(6609);   // 修改属性内容
            System.out.println(book);
        }
    }

    /**
     * 原子计算类
     * 累加器：DoubleAccumulator、LongAccumulator
     * 加法器：DoubleAdder、LongAdder
     */
    public static void test8() {
        {
            // 累加器
            DoubleAccumulator da = new DoubleAccumulator((x, y) -> x + y, 1.1);
            System.out.println("【累加器】原始存储内容：" + da.doubleValue());
            da.accumulate(20);  // 数据累加计算
            System.out.println("【累加器】新的存储内容：" + da.doubleValue());
        }
        {
            // 加法器
            DoubleAdder da = new DoubleAdder();
            da.add(10);
            da.add(20);
            da.add(30);
            System.out.println("【加法器】计算结果：" + da.doubleValue());
        }
    }
}

/**
 * 自定义一个引用类
 */
class Book {
    volatile long id;   // 不能使用private，必须使用volatile定义
    private String title;   // 标题
    private double price;   // 价格

    public Book(long id, String title, double price) {
        this.id = id;
        this.title = title;
        this.price = price;
    }

    public Book(String title, double price) {
        this.title = title;
        this.price = price;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Book book = (Book) o;
        return Double.compare(book.price, price) == 0 && Objects.equals(title, book.title);
    }

    @Override
    public int hashCode() {
        return Objects.hash(title, price);
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        AtomicLongFieldUpdater updater = AtomicLongFieldUpdater.newUpdater(Book.class, "id");
        updater.compareAndSet(this, this.id, id);   // CAS的修改操作
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    @Override
    public String toString() {
        return "【图书】ID：" + this.id + "、标题：" + this.title + "、价格：" + this.price;
    }
}